package org.summer.generator.handler;

import lombok.RequiredArgsConstructor;
import org.summer.generator.StringUtil;
import org.summer.generator.config.CreateConfig;
import org.summer.generator.config.ProjectConfig;
import org.summer.generator.log.Logger;
import org.summer.generator.log.LoggerManager;
import org.summer.generator.writer.FileWriter;
import org.summer.generator.writer.WriterToResource;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RequiredArgsConstructor
public class DefaultFileCreateHandler implements FileCreateHandler {
    private static final Logger log = LoggerManager.getLogger(DefaultFileCreateHandler.class);
    private final ProjectConfig project;
    private final CreateConfig create;

    @Override
    public void createDir() {
        List<String> packageNames = List.of(
                project.getEntityPackageName(),
                project.getMapperPackageName(),
                project.getRepositoryPackageName(),
                project.getServicePackageName(),
                project.getControllerPackageName(),
                project.getDtoPackageName()
        );
        String javaPathPrefix = new StringBuffer(BASE_DIR)
                .append(JAVA_PATH)
                .append(File.separator)
                .append(project.getBaseName().replace(".", File.separator))
                .append(File.separator)
                .append(project.getGroupName())
                .append(File.separator)
                .append(project.getModuleName())
                .toString();
        packageNames.forEach(n -> {
            boolean mkdirs = Paths.get(javaPathPrefix, n).toFile().mkdirs();
            log.debug("创建" + n + "层文件夹: " + mkdirs);
        });
        boolean xml = Paths.get(BASE_DIR, RESOURCES_PATH, project.getMapperXmlFilePath()).toFile().mkdirs();
        boolean ts = Paths.get(BASE_DIR, RESOURCES_PATH, project.getTypescriptTypeFilePath()).toFile().mkdirs();
        boolean tsAntd = Paths.get(BASE_DIR, RESOURCES_PATH, project.getTypescriptAntdTableColumnsFilePath()).toFile().mkdirs();
        boolean tsRedux = Paths.get(BASE_DIR, RESOURCES_PATH, project.getTypescriptReduxReducerFilePath()).toFile().mkdirs();
        log.debug("创建mybatis mapper XML文件夹： " + xml);
        log.debug("创建typescript文件夹： " + ts + tsAntd + tsRedux);
    }

    @Override
    public File createFile(Class<? extends FileWriter> fw, String fileName) {
//        log.debug("---------------------------------------------------分割线------------------------------------------------");
        WriterToResource annotation = fw.getAnnotation(WriterToResource.class);
        String classPrefix = fw.getSimpleName().replace(FileWriter.class.getSimpleName(), "");
        Pattern pattern = Pattern.compile("[A-Z][a-z]+");
        Matcher matcher = pattern.matcher(classPrefix);
        String keyWord = "";
        while (matcher.find()) {
            if ("Impl".equals(matcher.group())) {
            } else {
                keyWord += matcher.group();
            }
        }
        boolean flag = getFileCreateFlag(keyWord);
        File file = null;
        if (flag) {
            // 创建文件，并写入代码
            // 获取文件创建位置的包或者资源路径
            String dir = getFileCreateDir(keyWord, annotation);
//            log.debug("当前文件处理类【%s】，创建文件夹或包路径： %s".formatted(fw.getSimpleName(), dir));
            if (annotation == null) {
                boolean isImpl = classPrefix.toUpperCase().contains(IMPL.toUpperCase());
                if (classPrefix.contains("Entity")){
                    fileName =  fileName + JAVA_FILE_EXTENSION;
                }else {
                    fileName =  fileName + StringUtil.underlineCaseUpperCamel(dir) + (isImpl ? StringUtil.firstLetterUpperCase(IMPL) : "") + JAVA_FILE_EXTENSION;
                }
                file = createJavaFile(dir, fileName, isImpl);
            } else {
                file = createResourceFile(dir, fileName, annotation);
            }
        }
        log.info("当前文件处理类【%s】，创建文件标志： %s, 创建文件信息: %s".formatted(fw.getSimpleName(), flag, file));
        return file;
    }

    /**
     * 获取文件创建需要的包名，或者资源目录的文件夹名
     *
     * @param keyWord    反射方法关键字
     * @param annotation 文件创建类注解，需要确定文件的位置是类路径还是资源目录
     * @return 当前文件处理类处理的文件写入的文件夹位置
     */
    private String getFileCreateDir(String keyWord, WriterToResource annotation) {
        String dir = null;
        String reflectMethodName = "get" + keyWord;
        if (annotation == null) {
            reflectMethodName += "PackageName";
        } else {
            reflectMethodName += "FilePath";
        }
        try {
            Method method = project.getClass().getMethod(reflectMethodName);
            dir = method.invoke(project).toString();
        } catch (NoSuchMethodException e) {
            log.error("获取文件创建文件夹方法失败" + e);
            throw new RuntimeException(e);
        } catch (InvocationTargetException | IllegalAccessException e) {
            log.debug("获取文件创建文件夹反射调用方法失败" + e);
            throw new RuntimeException(e);
        }
        return dir;
    }

    /**
     * 获取文件创建标志，确定文件是否需要创建
     *
     * @param keyWord 反射方法关键字
     */
    private boolean getFileCreateFlag(String keyWord) {
        boolean flag = false;
        String reflectMethodName = "isCreate" + keyWord + "File";
        try {
            Method method = create.getClass().getMethod(reflectMethodName);
            flag = (Boolean) method.invoke(create);
        } catch (NoSuchMethodException e) {
            log.error("获取文件创建标志反射方法失败" + e);
            throw new RuntimeException(e);
        } catch (InvocationTargetException | IllegalAccessException e) {
            log.debug("获取文件创建标志反射调用方法失败" + e);
            throw new RuntimeException(e);
        }
        return flag;
    }

    /**
     * 创建java文件，创建文件之前使用createConfig检查文件是否真的需要创建
     *
     * @param isImpl java文件是否是接口实现类
     * @param packageName 文件创建的包名字
     * @param fileName    文件名字
     */
    File createJavaFile(String packageName, String fileName, boolean isImpl) {
//        log.debug("创建需要生成代码的java文件： " + packageName + " ,文件名字： " + fileName);
//        String javaFileName =  fileName + StringUtil.underlineCaseUpperCamel(packageName) + (isImpl ? StringUtil.firstLetterUpperCase(IMPL) : "") + JAVA_FILE_EXTENSION;
        File file = Paths.get(BASE_DIR, JAVA_PATH,
                project.getBaseName().replace(".", File.separator),
                project.getGroupName(),
                project.getModuleName(),
                packageName,
                isImpl ? IMPL : "",
                fileName
        ).toFile();
        if (isImpl){
            boolean flag = file.getParentFile().mkdirs();
//            log.debug("创建impl包: %s".formatted(flag));
        }
//        log.debug("创建文件处理类java文件路径：" + file.getPath());
        return file;
    }

    File createResourceFile(String dir, String fileName, WriterToResource annotation) {
//        log.debug("创建需要生成代码资源文件；文件目录：%s，文件名：%s，文件名后缀：%s，文件扩展名：%s".formatted(dir, fileName, annotation.suffix(), annotation.extension()));
        String resource = RESOURCES_PATH;
        if (annotation.toTest()){
            resource = TEST_RESOURCES_PATH;
        }
        File file = Paths.get(BASE_DIR,
                resource,
                    dir,
                    fileName + annotation.suffix() + annotation.extension()
        ).toFile();
        if (annotation.toTest()){
            boolean f = file.getParentFile().mkdirs();
//            log.debug("创建测试资源文件夹：%s".formatted(f));
        }
//        log.debug("创建资源文件path：" + file.getPath());
        return file;
    }
}
